package org.iottree.driver.common;

/**
 摘 要：通过数据监视，分析的方法，找出了PPI协议的关键报文格式，可用于上位机、现场设备与S7-200 CPU之间通讯。
关键字：PLC ，PPI ，协议
1 前言
西门子S7-200 PLC之间或者PLC与PC之间通信有很多种方式:自由口，PPI方式，MPI方式，Profibus方式。使用自由口方式进行编程时，在上位机和PLC中都要编写数据通信程序。使用PPI协议进行通信时，PLC可以不用编程，而且可读写所有数据区，快捷方便。但是西门子公司没有公布PPI协议的格式。用户如果想使用PPI协议监控，必须购买其监控产品或第三方厂家的组态软件。这样给用户自主开发带来一定困难，特别是自行开发的现场设备就不能通过PPI协议接入PLC。其它通讯方式编程也存在编程复杂，需要购买软件和授权等局限性(1)。通过数据监视、分析的方法，我们找出了PPI协议的关键报文格式，可用于上位机、现场设备与S7-200 CPU之间通讯。
2 分析方法
西门子的Step 7 Micro/Win32 是用于S7-200系列PLC的开发工具，它使用PC机上的COM口通过一条PC/PPI编程电缆连到PLC的编程口上。这说明，PC实际上是可以通过串口同S7-200 CPU通讯。只是我们不知道通讯协议而已。通过截获PC机串口上的收发数据，对照Step 7软件发出的指令，我们就有可能分析出有关指令的报文和通讯方式；然后，直接通过串口向PLC发送报文，以验证这些指令报文是否正确。本着这一思想，我们采用以下步骤获得这些报文。
首先制作一个串口的分支器，COM1的RX、TX分别接到COM2的TX、RX，即交叉接线，使得COM1发的数据COM2能收到。PC/PPI编程电缆接在COM1上，这样，Step7 Micro/Win32发给PLC的报文就可以在COM2上接收了。我们按S7-200系统手册设置好两个串口，参数要一样，均为9600，8，偶校验，1位停止位。然后设置好Step7软件，使之能与S7-200 CPU正常通讯。从Step7软件中发出一个明确指令，COM2上的监视软件就能显示这条报文了（用16进制显示）。通过与Profibus标准的类比(2)我们就可以得到一些关键的报文了。这种方法比分析PLC中NETR，NETW指令要直接、全面(3)。
3 PPI协议分析
PC与PLC采用主从方式通讯，PC按如下的格式发读写指令，PLC作出接收正确的响应（返回应答数据E5H或F9H见下文分析），上位机接到此响应则发出确认命令（10 02 5C 5E 16），PLC再返回给上位机相应数据。
SD LE LEr SD DA SA FC DSAP SSAP DU FCS ED
SD:开始符（68H） LE、Ler：长度（从DA到DU）
DA：目的地址 SA：源地址
FC：功能码 （6CH） DSAP：目的服务存取点
SSAP：源服务存取点 DU：数据单元
FCS：校验和 ED：结束符（16H）
3.1 读命令分析
一次读一条数据
对于一次读取一个数据，读命令都是33个字节。前面的0—21字节是相同的，为 ：
68 1B 1B 68 02 00 6C 32 01 00 00 00 00 00 0E 00 00 04 01 12 0A 10
因为是PC上发的读PLC数据的命令，SA=00，DA=02，如果有多个站，DA要改成相应的站号。读命令中从DA到DU的长度为1B即27个字节。从22字节开始根据读取数据的类型、位置不同而不同。表一是读不同存储器命令的Byte22—32。
字节 22 23 24 25 26 27 28 29 30 31 32
功能 读取长度 数据个数* 存储器类型 偏移量 校验 结束
读q0.0 01 00 01 00 00 82 00 00 00 64 16
读m0.0 01 00 01 00 00 83 00 00 00 65 16
读M0.1 01 00 01 00 00 83 00 00 01 66 16
读SMB34 02 00 01 00 00 05 00 01 10 F9 16
读VB100 02 00 01 00 01 84 00 03 20 8B 16
读VW100 04 00 01 00 01 84 00 03 20 8D 16
读vd100 06 00 01 00 01 84 00 03 20 8F 16
读i0.5 01 00 01 00 00 81 00 00 05 68 16"
读i0.7 01 00 01 00 00 81 00 00 07 6A 16"
表 一 读命令的Byte22-32
从表中我们可以得出以下结果：
Byte 22 读取数据的长度
01：1 Bit 02：1 Byte
04：1 Word 06：Double Word
Byte 24数据个数,这里是01 ，一次读多个数据时见下面的说明。
Byte 26 存储器类型，01：V存储器 00：其它
Byte 27 存储器类型
04：S 05：SM 06：AI 07：AQ 1E: C
81：I 82：Q 83：M 84：V 1F: T
Byte 28,29,30存储器偏移量指针（存储器地址*8），如：VB100，存储器地址为100，偏移量指针为800,转换成16进制就是320H,则Byte 28—29这三个字节就是：00 03 20。
Byte 31 校验和，前面已说到这是从(DA+SA+DSAP+SSAP+DU) Mod 256 。
一次读多条数据
对于一次读多个数据的情况，前21Byte与上面相似只是长度LD，LDr及Byte 14不同：
Byte 14 数据块占位字节，它指明数据块占用的字节数。与数据块数量有关，长度=4+数据块数*10,如：一条数据时为4+10=0E(H)；同时读M,V,Q三个不同的数据块时为4+3*10=22(H)。
Byte 22 总是02 即以Byte为单位。
Byte 24 以字节为单位，连续读取的字节数。如读2个VD则Byte24=8
Byte 19---30 按上述一次读一个数据的格式依次列出，
Byte 31---42 另一类型的数据，也是按上述格式给出。
以此类推，一次最多读取222个字节的数据。
3.2 写命令分析
一次写一个Double Word类型的数据，写命令是40个字节，其余为38个字节。
写一个Double Word类型的数据，前面的0—21字节为 ：
68 23 23 68 02 00 6C 32 01 00 00 00 00 00 0E 00 00 04 01 12 0A 10
写一个其它类型的数据，前面的0—21字节为 ：（与上面比较，只是长度字节发生变化）
68 21 21 68 02 00 6C 32 01 00 00 00 00 00 0E 00 00 04 01 12 0A 10
从22字节开始根据写入数据的值和位置不同而变化。表二是几个写命令的Byte22—40。
字 节 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
写入位置及值 长度 个数 类型 偏移量 位数 值、校验码、结束符
M0.0=1 01 00 01 00 00 83 00 00 00 00 03 00 01 01 00 71 16
M0.0=0 01 00 01 00 00 83 00 00 00 00 03 00 01 00 00 70 16
M0.1=1 01 00 01 00 00 83 00 00 01 00 03 00 01 01 00 72 16
vb100=10 02 00 01 00 01 84 00 03 20 00 04 00 08 10 00 AE 16
vb100=FF 02 00 01 00 01 84 00 03 20 00 04 00 08 FF 00 9D 16
VW100=FFFF 04 00 01 00 01 84 00 03 20 00 04 00 10 FF FF A6 16
VD100=FFFFFFFF 06 00 01 00 01 84 00 03 20 00 04 00 20 FF FF FF FF B8 16
表二 写命令的Byte22—40
经分析我们可以得出以下结果：
Byte 22-- Byte 30 写入数据的长度、存储器类型、存储器偏移量与读命令相同。T，C等不能用写命令写入。
Byte 32 如果写入的是位数据这一字节为03，其它则为04
Byte 34 写入数据的位数
01: 1 Bit 08: 1 Byte 10H: 1 Word 20H: 1 Double Word
Byte 35--40值、校验码、结束符
如果写入的是位、字节数据，Byte35就是写入的值，Byte36=00，Byte37=检验码，Byte38=16H，结束。如果写个的是字数据（双字节），Byte35,Byte36就是写入的值， Byte37=检验码，Byte38=16H，结束。如果写个的是双字数据（四字节），Byte35—38就是写入的值， Byte39=检验码，Byte40=16H，结束。
3.3 其它命令分析
强制写入
I、Q、S 等不能使用上述的写命令写入数据，只能用强制写入的方式。
前0—35字节值如下（长度字段要根据实际情况而定）,需要注意的是Byte8=07,
68 2B 2B 68 02 00 6C 32 07 00 00 00 00 00 0C 00 12 00 01 12 08 12 48 0B 00 00 00 00 00 FF 09 00 0E 00 01 10
后面的内容如下：
Byte 32 占位字节，从下一字节开始到校验和前的字节数。说明同读数据的Byte 14.
Byte 36 强制写入数据的长度
01：1 Bit 02：1 Byte
04：1 Word 06：Double Word
Byte 38 数据个数,这里是01 ，一次强制写多个数据时见下面的说明。
Byte 40 存储器类型
Byte 41 存储器类型，见读命令的说明。
Byte 42、43、44存储器偏移量指针（存储器地址*8）
Byte 45、46、47、48 值、校验码、结束符
取消强制写
强制写入I、Q 等后，这些值就不能被程序改变，除非使用”取消强制命令”。 取消强制命令的格式与强制写入相似，变化的有以下几点：（1）是没有”值”这一段，即没有Byte45—48。这影响到长度字节LE，LEr；占位字节Byte 32.（2）Byte16=10H, (3) Byte32=0CH，也就是第一条，没有”值”这一段，数据块长度变短了。
对于一次强制写入或取消多个数据的情况可以参照写入命令写出相应的报文，这里不再给出。
STOP命令
STOP命令使得S7-200 CPU从RUN状态转换到STOP状态（此时CPU模块上的模式开关开应打在RUN或TERM位置）。PC发出如下命令，PLC返回F9，此时PLC已进入等待状态，PC再发确认报文（10 02 5C 5E 16）,完成一个命令过程。
68 1D 1D 68 02 00 6C 32 01 00 00 00 00 00 10 00 00 29 00 00 00 00 00 09 50 5F 50 52 4F 47 52 41 4D AA 16
RUN 命令
RUN命令使得S7-200 CPU从STOP状态转换到RUN状态（此时CPU模块上的模式开关开应打在RUN或TERM位置）。PC发出下命令，PLC返回F9，此时PLC已进入运行状态，PC再发确认报文（10 02 5C 5E 16），完成一个命令过程。
68 21 21 68 02 00 6C 32 01 00 00 00 00 00 14 00 00 28 00 00 00 00 00 00 FD 00 00 09 50 5F 50 52 4F 47 52 41 4D AA 16
3.4 读出数据分析
一次读出一条数据
PLC响应的数据也是用PPI封装的。如果用一次读一条数据命令，响应的报文中就只包含一条数据，此响应报文的Byte16<=8。
Byte 04：DA=00 Byte 05：SA=02 即从02 PLC站发往PC。
Byte 16：数据块占位字节，从Byte21到校验和前的字节数。
一条数据时：Word=06 Double Word=08 其它为 05。
Byte 22：数据类型，位=3，其它=4。
Byte 24：数据宽度，Bit=01,Byte=08,Word=10H,Double Word=20H
Byte 25—28：值。
如果网络上只可能有一个站会发回响应报文，那么可以简单的根据LE长度字节判断返回值的位置：LE=16H，返回值是字节，或位类型的值，响应报文的Byte 25即是返回值；LE=17H，返回值是字（双字节）类型的值，响应报文的Byte 25，26即是返回值；LE=19H，返回值是双字（四字节）类型的值，响应报文的Byte 25—28即是返回值。更准确的方式是要根据返回报文的SA，DA，及存储器位置等信息识别目标地址和源地址，确认是这次申请的返回数据，然后经过校验检查，得到正确的数据。
一次读出多条数据
如果用的是一次读多条数据的命令，响应的报文中就包含有多条数据。这些数据只有类型参数，没有偏移量参数，所以要注意根据读命令的顺序将其一一对应起来。
Byte 16：数据块占位字节，从Byte21到校验和前的字节数，与数据块数量和类型有关。
Byte 20：数据块的个数。
Byte 21 开始为数据块，每一个数据块都以FF 04开始，接下来的两个字节表示这一数据块的长度，以位计算，然后依次是连续的数据。下一个数据块也是以FF 04开始，重复上述格式，直到结束。
4 应用
PC与与PLC通讯
在采用PC机与PLC通讯时，计算机采用PPI电缆或普通的485串口卡与PLC的编程口连接， PC机采用VB编程，遵循PPI协议，主从式的通讯方式，一次读写操作的步骤包括：首先上位机发出读写命令，PLC作出接收正确的响应（返回应答数据E5H），上位机接到此响应则发出确认命令（10 02 5C 5E 16），PLC完成正确的读写响应，返回给上位机相应数据。这样收发两次数据，完成一次数据的读写。那么我们就可以利用上述PPI协议，读写S7-200PLC中的各种类型数据，包括I、Q、SM、M、V、T、C、S等数据类型，能够直接读出以上变量中的位、字节、字、双字等，（其中读位变量时，实际是读取该位所在的字节值）。可以改变PLC的运行状态（RUN/STOP）。 在编程时，最好将读取的检测值、输出值等数据，存放在PLC的一个连续的变量区中，当上位机读取PLC的数据时，就可以一次读出这组连续的数据，减少数据的分次频繁读取。当修改设定值等数据时，进行写数据的通讯操作。
现场设备与PLC通讯
利用PPI协议除了能与上位机（PC）通讯外，更重要的是为现场设备与S7-200CPU之间的通讯提供了捷径。自行开发的设备可以方便的利用PPI协议通过485/232接口接入S7-200CPU，联入PLC的网络，包括控制面板，采集器等。
5 总结
通过分析STEP7 Micro/win32软件与S7-200CPU的通讯数据，我们得到了西门子PPI协议的关键报文格式，这一结果对工程实践具有较高的参考价值。在不使用西门子或其它组态软件的情况下，利用分析得到的PPI协议实现了上位机对PLC的监控。现场设备与PLC通讯方面的工作正在进行中。另外这种对通讯端口进行监测、分析的方法也对一些未知协议的测定和通讯错误的检查具有指导意义。
 */
public class SiemensPPIDrv
{
	
}
